/*
 * BiblioDeCanciones.cpp
 *
 *  Created on: 12/04/2013
 *      Author: pato
 */

#include "BiblioDeCanciones.h"

BiblioDeCanciones::BiblioDeCanciones() {
	this->origen = new string("canciones/");
	this->destino = new string(".");
	this->EstaCreado = false;
	this->CrearEstructuras();
}

int BiblioDeCanciones::BorrarID(unsigned int id) {
	int retorno = 0;
	this->CrearEstructuras();
	NormalizadorTxt* normalizador = new NormalizadorTxt();
	char* aux_text = (char*) malloc(MB1);
	char aux_cancion[100];
	char aux_idioma[100];
	char aux_artista[100];
	char* pauxi;
	char* pauxf;
	char* paux1;
	char* paux2;
	char* paux3;
	bool existeAnio = false;
	string* anio;
	//Cargo archivo en cadena.
	string* pstring;
	pstring = this->biblioteca->Buscar(id);
	if (!pstring) {
		cout<<"NO SE ENCUENTRA ESE ID PARA SER BORRADO"<<endl;
		return -1;
	}
	strcpy(aux_text,pstring->c_str());
	//COMRPOBAR FORMATO
	paux1 = strstr(aux_text,"-");
	paux2 = strstr(paux1+1,"-");
	paux3 = strstr(paux2+1,"-");
	pauxf = strstr(aux_text,"\n");
	if (!paux1 || !paux2 || !pauxf) {
		retorno = -1;
	}
	if (paux2 > pauxf) {
		retorno = -1;
	}
	if (paux3 && paux3 < pauxf) {
		existeAnio = true;
	} else {
		existeAnio = false;
	}
	string* text = new string(aux_text);
	//Parseo Autor
	pauxi = aux_text;
	pauxf = strstr(pauxi,"-");
	if (!pauxf) {
		retorno = -1;
	} else {
		strncpy(aux_artista,pauxi,(pauxf - pauxi));
		strncpy(&(aux_artista[pauxf - pauxi]), "\0", 1);
	}
	string* artista = new string(aux_artista);
	//Parsear Anio(Opcional)
	if (existeAnio && retorno != -1) {
		char aux_anio[MB1];
		pauxi = pauxf;
		pauxi++;
		pauxf = strstr(pauxi,"-");
		if (!pauxf) {
			retorno = -1;
		} else {
			strncpy(aux_anio,pauxi,(pauxf - pauxi));
			strncpy(&(aux_anio[pauxf - pauxi]), "\0", 1);
		}
		anio = new string(aux_anio);
	}
	//Parsear titulo
	pauxi = pauxf;
	pauxi++;
	pauxf = strstr(pauxi,"-");
	if (!pauxf) {
		retorno = -1;
	} else {
		strncpy(aux_cancion,pauxi,(pauxf - pauxi));
		strncpy(&(aux_cancion[pauxf - pauxi]), "\0", 1);
	}
	string* cancion = new string(aux_cancion);

	//Parsear Idioma
	pauxi = pauxf;
	pauxi++;
	pauxf = strstr(pauxi,"\n");
	if (!pauxf) {
		retorno = -1;
	} else {
		strncpy(aux_idioma,pauxi,(pauxf - pauxi));
		strncpy(&(aux_idioma[pauxf - pauxi]), "\0", 1);
	}
	string* idioma = new string(aux_idioma);
	//Borrar de estructuras
	this->biblioteca->Borrar(id);
	normalizador->normalizarPalabra(artista);
	normalizador->normalizarPalabra(cancion);
	int posi = 0;
	int posf = 0;
	string str_aux;
	while (string::npos != artista->find(";",posi)) {
		posf = artista->find(";",posi);
		str_aux = artista->substr (posi,posf-posi);
		this->indiceAutores->Borrar(Clave(str_aux),id);
		posi = posf + 1;
	}
	str_aux = artista->substr (posi,artista->length()- posi);
	this->indiceAutores->Borrar(Clave(str_aux),id);
	cout << "Titulo a borrar: " << *cancion << endl;
	this->indiceTitulos->baja(*cancion,id);
	this->parser_canciones->eliminarTextoDeIndiceInvertido(text, this->indiceInvertido,id);
	if (existeAnio) { delete anio;}
	delete idioma;
	delete cancion;
	delete artista;
	delete text;
	free(aux_text);
	delete normalizador;
	return retorno;
}

void BiblioDeCanciones::BorrarTodo() {
	if (this->EstaCreado) {
			delete this->indiceAutores;
			delete this->indiceTitulos;
			delete this->biblioteca;
			delete this->indiceInvertido;
			delete this->parser_canciones;
	}

	string* archivos[14];
	string ruta=PATH_ARCHIVO_RV;
	archivos[0] = new string(ruta +=".bin");
	ruta=PATH_ARCHIVO_RV;
	archivos[1] = new string(ruta += "e.bin");
	ruta=PATH_ARBOL;
	archivos[2] = new string(PATH_ARBOL);
	archivos[3] = new string(ruta += "bitmap.bin");
	ruta=PATH_INDICE_INVERTIDO;
	ruta+=PATH_ARBOL_INVERTIDO;
	archivos[4] = new string(ruta);
	archivos[5] = new string(ruta+= "bitmap.bin");
	ruta=PATH_HASH_AUXILIAR;
	archivos[6] = new string(ruta);
	archivos[7] = new string(ruta += "bitmap.bin");
	string path=PATH_HASH_AUXILIAR;
	int pos = path.rfind('.');
		string path2 = path.substr(0, pos);
		path2 += "tabla";
	archivos[8] = new string(path2 + ".bin");
	archivos[9] = new string(path2 + "e.bin");
	ruta=PATH_HASH_TITULOS;
	archivos[10] = new string(ruta);
	archivos[11] = new string(ruta += "bitmap.bin");
	path=PATH_HASH_TITULOS;
		pos = path.rfind('.');
			path2 = path.substr(0, pos);
			path2 += "tabla";
	archivos[12] = new string(path2 + ".bin");
	archivos[13] = new string(path2 + "e.bin");
//	archivos[0] = new string(PATH_ARBOL_INVERTIDO);
//	archivos[1] = new string(PATH_LISTA_INVERTIDO);
//	archivos[2] = new string(PATH_ARBOL);
//	archivos[3] = new string(PATH_HASH_TITULOS);
//	archivos[4] = new string(PATH_INDICE_INVERTIDO);
//	char cadena[100];
//	strcpy(cadena,PATH_ARCHIVO_RV);
//	archivos[5] = new string(strcat(cadena,".bin"));
//	archivos[6] = new string(strcat(cadena,"e.bin"));
//
//	string PATH_HASH_TITULOS_TABLA =PATH_HASH_TITULOS;
//	PATH_HASH_TITULOS_TABLA += "tabla.bin";
//
//	string PATH_HASH_TITULOS_TABLAE =PATH_HASH_TITULOS;
//	PATH_HASH_TITULOS_TABLAE += "tablae.bin";
//
//	string PATH_INDICE_INVERTIDO_TABLA = PATH_INDICE_INVERTIDO;
//	PATH_INDICE_INVERTIDO_TABLA += "tablae.bin";
//
//	string PATH_INDICE_INVERTIDO_TABLAE = PATH_INDICE_INVERTIDO;
//	PATH_INDICE_INVERTIDO_TABLAE += "tablae.bin";
//
//	archivos[7] = new string(PATH_HASH_TITULOS_TABLA);
//	archivos[8] = new string(PATH_HASH_TITULOS_TABLAE);
//	archivos[9] = new string(PATH_INDICE_INVERTIDO_TABLA);
//	archivos[10] = new string(PATH_INDICE_INVERTIDO_TABLAE);


	for(int i=0;i<=13;i++) {
		string cadenaConcatenada;
		cadenaConcatenada+=(*this->destino);
		cadenaConcatenada+=(*archivos[i]);
		if( remove(cadenaConcatenada.c_str() ) == -1 ) {
			cout << "NO SE PUDO BORRAR EL ARCHIVO"<<i<<endl;
		}
		delete archivos[i];
	}
	this->EstaCreado = false;

	this->CrearEstructuras();

}

void BiblioDeCanciones::CrearEstructuras() {
	if (!this->EstaCreado) {
		string rutaHash  = *this->destino;
		rutaHash += PATH_HASH_TITULOS;
		this->indiceTitulos = new HashExtensible(rutaHash , "char*", MB1);
		this->biblioteca = new RegistroCanciones(*this->destino);
		string rutaArbol  = *this->destino;
		rutaArbol += PATH_ARBOL;
		this->indiceAutores = new ArbolBMas(rutaArbol,"char*");
		string rutaIndice  = *this->destino;
		rutaIndice += PATH_INDICE_INVERTIDO;
		this->indiceInvertido = new IndiceInvertido(rutaIndice);
		this->parser_canciones = new ParserCanciones(PATH_STOPWORDS);

		this->EstaCreado = true;
	}
}

BiblioDeCanciones::~BiblioDeCanciones() {
	delete this->destino;
	delete this->origen;
	if (this->EstaCreado) {
		delete this->indiceAutores;
		delete this->indiceTitulos;
		delete this->biblioteca;
		delete this->indiceInvertido;
		delete this->parser_canciones;
	}
}

int BiblioDeCanciones::IndexarCancion(string path) {
	//this->CrearEstructuras();
	NormalizadorTxt* normalizador = new NormalizadorTxt();
	char* aux_text = (char*) malloc(MB1);
	char aux_cancion[100];
	char aux_idioma[100];
	char aux_artistas[200];
	char* pauxi;
	char* pauxf;
	char* paux1;
	char* paux2;
	char* paux3;
	bool existeAnio = false;
	string* anio;
	fstream archivo;
	int retorno = 0;
	archivo.open(path.c_str(), fstream::in);
	if (!archivo.good()) {
		retorno = -1;
		free(aux_text);
		delete normalizador;
		return retorno;
	}
	//Cargo archivo en cadena.
	archivo.read(aux_text,MB1);
	//COMRPOBAR FORMATO
	paux1 = strstr(aux_text,"-");
	paux2 = strstr(paux1+1,"-");
	paux3 = strstr(paux2+1,"-");
	pauxf = strstr(aux_text,"\n");
	if (!paux1 || !paux2 || !pauxf) {
		retorno = -1;
		free(aux_text);
		delete normalizador;
		return retorno;
	}
	if (paux2 > pauxf) {
		retorno = -1;
		free(aux_text);
		delete normalizador;
		return retorno;
	}
	if (paux3 && paux3 < pauxf) {
		existeAnio = true;
	} else {
		existeAnio = false;
	}
	string* text = new string(aux_text);
	//Parseo Autor
	pauxi = aux_text;
	pauxf = strstr(pauxi,"-");
	if (!pauxf) {
		retorno = -1;
		delete text;
		free(aux_text);
		delete normalizador;
		return retorno;
	} else {
		strncpy(aux_artistas,pauxi,(pauxf - pauxi));
		strncpy(&(aux_artistas[pauxf - pauxi]), "\0", 1);
	}
	string* artistas = new string(aux_artistas);
	//Parsear Anio(Opcional)
	if (existeAnio && retorno != -1) {
		char aux_anio[MB1];
		pauxi = pauxf;
		pauxi++;
		pauxf = strstr(pauxi,"-");
		if (!pauxf) {
			retorno = -1;
			delete artistas;
			delete text;
			free(aux_text);
			delete normalizador;
			return retorno;
		} else {
			strncpy(aux_anio,pauxi,(pauxf - pauxi));
			strncpy(&(aux_anio[pauxf - pauxi]), "\0", 1);
		}
		anio = new string(aux_anio);
	}
	//Parsear titulo
	pauxi = pauxf;
	pauxi++;
	pauxf = strstr(pauxi,"-");
	if (!pauxf) {
		retorno = -1;
		if (existeAnio) { delete anio;}
		delete artistas;
		delete text;
		free(aux_text);
		delete normalizador;
		return retorno;
	} else {
		strncpy(aux_cancion,pauxi,(pauxf - pauxi));
		strncpy(&(aux_cancion[pauxf - pauxi]), "\0", 1);
	}
	string* cancion = new string(aux_cancion);

	//Parsear Idioma
	pauxi = pauxf;
	pauxi++;
	pauxf = strstr(pauxi,"\n");
	if (!pauxf) {
		retorno = -1;
		if (existeAnio) { delete anio;}
		delete cancion;
		delete artistas;
		delete text;
		free(aux_text);
		delete normalizador;
		return retorno;
	} else {
		strncpy(aux_idioma,pauxi,(pauxf - pauxi));
		strncpy(&(aux_idioma[pauxf - pauxi]), "\0", 1);
	}
	string* idioma = new string(aux_idioma);
	//Agregar a estructuras
	normalizador->normalizarPalabra(text);
	short unsigned int id = this->biblioteca->Agregar(*text);
	//Habria q comprobar q se agregaron bien
	normalizador->normalizarPalabra(artistas);
	normalizador->normalizarPalabra(cancion);
	int posi = 0;
	int posf = 0;
	string str_aux;
	while (string::npos != artistas->find(";",posi)) {
		posf = artistas->find(";",posi);
		str_aux = artistas->substr (posi,posf-posi);
		this->indiceAutores->Agregar(Clave(str_aux),id);
		posi = posf + 1;
	}
	str_aux = artistas->substr (posi,artistas->length()- posi);
	this->indiceAutores->Agregar(Clave(str_aux),id);
	this->indiceTitulos->Agregar(*cancion,id);
	this->parser_canciones->Parsear(text, this->indiceInvertido,id);

	if (existeAnio) { delete anio;}
	delete idioma;
	delete cancion;
	delete artistas;
	delete text;
	free(aux_text);
	delete normalizador;
	return retorno;
}

void BiblioDeCanciones::Indexar() {
	string rutaAuxiliar;
	DIR *dir;
	struct dirent *ent;
	dir = opendir (this->origen->c_str());
	cout << "Directorio: " << *this->origen << endl;
	if (dir == NULL) {
		cout<< "No puedo abrir el directorio" << endl;
	}
	while ((ent = readdir (dir)) != NULL) {
	      if ( strcmp(ent->d_name, this->origen->c_str()) != 0 ) {
	    	  rutaAuxiliar = ent->d_name;
	    	  string path;
	    	  path = *(this->origen) + rutaAuxiliar;
	    	  if(strstr(path.c_str(),".txt")) {
	    		  this->IndexarCancion(path);
	    	  }
	      }
	}
	closedir (dir);
}

int BiblioDeCanciones::NuevoOrigen(string origen ) {
	bool RutaApropiada =  this->ComprobarPath(origen);
	if (RutaApropiada) {
		this->origen->assign(origen);
		return 0;
	} else {
		return -1;
	}
}

int BiblioDeCanciones::NuevoDestino(string destino ) {
	bool RutaApropiada =  this->ComprobarPath(destino);
	if (RutaApropiada) {
		this->destino->assign(destino);
		return 0;
	} else {
		return -1;
	}
}

void BiblioDeCanciones::BuscarAutor(string *autor) {
	NormalizadorTxt* normalizador = new NormalizadorTxt();
	normalizador->normalizarPalabra(autor);
	list<unsigned int>* lista_canciones = this->indiceAutores->buscarClave(*autor);
	list<unsigned int>::const_iterator it;
	unsigned int id;
	string * cancion;
	string auxiliar;
	cout << "OCURRENCIAS PARA LA BUSQUEDA DE AUTOR = "<< *autor << endl << endl;
	if (!lista_canciones){
		cout << "NO EXISTEN COINCIDENCIAS "<< endl;
	} else {
		for (it = lista_canciones->begin(); it != lista_canciones->end(); ++it) {
			id = (unsigned int) *it;
			cancion = this->biblioteca->Buscar(id);
			auxiliar = "";
			auxiliar = cancion->substr(0,cancion->find("\n"));
			cout << "ID : " << id << endl << auxiliar << endl;
			delete cancion;
		}
		delete lista_canciones;
	}
	delete normalizador;
	return;
}
void BiblioDeCanciones::BuscarTitulo(string *titulo ) {
	NormalizadorTxt* normalizador = new NormalizadorTxt();
	normalizador->normalizarPalabra(titulo);
	list<unsigned int>* lista_canciones = this->indiceTitulos->BuscarClave(*titulo);
	list<unsigned int>::const_iterator it;
	unsigned int id;
	string * cancion;
	string auxiliar;
	cout << "OCURRENCIAS PARA LA BUSQUEDA DE TITULO = "<< *titulo << endl << endl;
	if (!lista_canciones){
		cout << "NO EXISTEN COINCIDENCIAS "<< endl;
	} else {
		for (it = lista_canciones->begin(); it != lista_canciones->end(); ++it) {
			id = (unsigned int) *it;
			cancion = this->biblioteca->Buscar(id);
			auxiliar = "";
			auxiliar = cancion->substr(0,cancion->find("\n"));
			cout << "ID : " << id << endl << auxiliar << endl;
			delete cancion;
		}
		delete lista_canciones;
	}
	delete normalizador;
	return;
}

void BiblioDeCanciones::BuscarLetra(string *frase ) {
	NormalizadorTxt* normalizador = new NormalizadorTxt();
	normalizador->normalizarPalabra(frase);
	list<unsigned int>* lista_canciones = this->indiceInvertido->BuscarFrase(*frase);
	list<unsigned int>::const_iterator it;
	unsigned int id;
	string * cancion;
	string auxiliar;
	if (!lista_canciones){
			cout << "NO EXISTEN COINCIDENCIAS "<< endl;
	} else {
		cout << "OCURRENCIAS PARA LA BUSQUEDA DE FRASE = "<< *frase << endl << endl;
		for (it = lista_canciones->begin(); it != lista_canciones->end(); ++it) {
			id = (unsigned int) *it;
			cancion = this->biblioteca->Buscar(id);
			auxiliar = "";
			auxiliar = cancion->substr(0,cancion->find("\n"));
			cout << "ID : " << id << endl << auxiliar << endl;
			delete cancion;
		}
		delete lista_canciones;
	}
	delete normalizador;
	return;
}

void BiblioDeCanciones::MostrarCancion(unsigned int id) {
	string *cancion = this->biblioteca->Buscar(id);
	if (cancion) {
		cout << *cancion;
	} else {
		cout<<"NO SE ENCUENTRA ESE ID PARA MOSTRAR"<<endl;
	}
	delete cancion;
}

bool BiblioDeCanciones::ComprobarPath(string origen) {
    if ( origen.c_str() == NULL) {
    	return false;
    }
    DIR *pDir;
    bool existe = false;
    pDir = opendir (origen.c_str());
    if (pDir != NULL) {
    	existe = true;
        (void) closedir (pDir);
    }
    return existe;
}

ArbolBMas* BiblioDeCanciones::getIndiceAutores() {
	return this->indiceAutores;
}

HashExtensible* BiblioDeCanciones::getIndiceTitulos() {
	return this->indiceTitulos;
}

IndiceInvertido* BiblioDeCanciones::getIndiceInvertido() {
	return this->indiceInvertido;
}

RegistroCanciones* BiblioDeCanciones::getRegistroCanciones() {
	return this->biblioteca;
}
